package com.square.service.common.handler;

import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.exceptions.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.ShiroException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Iterator;
import java.util.Objects;

/**
 * @author : 18.40
 * @date : 2020/04/09 15:08
 * @description : 全局异常捕获
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 集成@Valid & @RestControllerAdvice
     *
     * @param e
     * @return
     */
    @ExceptionHandler(BindException.class)
    public R<?> exceptionHandler(BindException e) {
        StringBuilder msg = new StringBuilder();
        for (int i = 0; i < e.getAllErrors().size(); i++) {
            msg.append(e.getAllErrors().get(i).getDefaultMessage()).append(";");
        }
        return R.failed(msg.toString());
    }

    /**
     * 集成@Validated & @RestControllerAdvice
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public R<?> constraintViolationExceptionHandler(ConstraintViolationException e) {
        StringBuilder msg = new StringBuilder();
        Iterator it = e.getConstraintViolations().iterator();
        while (it.hasNext()) {
            msg.append(((ConstraintViolation) it.next()).getMessage()).append(";");
        }
        return R.failed(msg.toString());
    }

    /**
     * 参数空指针
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public R<?> missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e) {
        return R.failed("参数[" + e.getParameterName() + "]为空");
    }

    /**
     * 集成@Valid & @RequestBody & @RestControllerAdvice
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R<?> illegalParamExceptionHandler(MethodArgumentNotValidException e) {
        StringBuilder msg = new StringBuilder();
        for (int i = 0; i < e.getBindingResult().getAllErrors().size(); i++) {
            msg.append(e.getBindingResult().getAllErrors().get(i).getDefaultMessage()).append(";");
        }
        return R.failed(msg.toString());
    }

    /**
     * 请求方法不支持
     *
     * @param exception
     * @return
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    public R<?> methodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException exception) {
        String supportedMethods = Objects.requireNonNull(exception.getSupportedHttpMethods()).toString();
        String msg = "请求方法不合法,请使用方法" + supportedMethods;
        return R.failed(msg);
    }

    /**
     * 全局异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public R<?> exceptionHandler(Exception e) {
        log.error(e.getMessage(), e);
        return R.failed(ApiCode.INTERNAL_SERVER_ERROR);
    }

    /**
     * 自定义异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ApiException.class)
    public R<?> exceptionHandler(ApiException e) {
        log.error(e.getMessage(), e);
        return R.failed(e.getErrorCode());
    }

    /**
     * shiro异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ShiroException.class)
    public R<?> exceptionHandler(ShiroException e) {
        log.error(e.getMessage(), e);
        return R.failed(e.getMessage());
    }

}
